﻿using System;

namespace Centido.Core.Test
{
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Changing security structure
    /// </summary>
    [TestClass]
    public class ChangingSecurityStructureTest
    {
        /// <summary>
        /// Domain name
        /// </summary>
        public const string DomainName = "FullAdminRights";

        /// <summary>
        /// Another role
        /// </summary>
        private Role _anotherRole;

        /// <summary>
        /// A child role
        /// </summary>
        private Role _childRole;

        /// <summary>
        /// Domain
        /// </summary>
        private Domain _domain;

        /// <summary>
        /// A role
        /// </summary>
        private Role _role;

        /// <summary>
        /// A table
        /// </summary>
        private Table _table;

        private Unit _unit0;
        private Unit _unit1;
        private Unit _unit11;
        private Unit _unit111;
        private Unit _unit112;
        private Unit _unit2;
        private Unit _unit21;
        private Unit _unit211;

        private User _user01;
        private User _user1111;
        private User _user1121;
        private User _user111;
        private User _user112;
        private User _user11;
        private User _user2111;
        private User _user211;
        private User _user21;

        /// <summary>
        /// Test initialize
        /// </summary>
        /// <remarks>
        ///   0:(01) 1:(11)         2:(21)
        ///    |         |          |
        ///   11:(111, 112)         21:(211, 111)
        ///    |         |          | 
        ///   111:(1111) 112:(1121) 211:(2111)
        /// 
        ///   role (ChildAndParentUnits) : childRole
        ///   childRole (ChildUnits) : 01, 11, 111, 112, 1111, 1121
        ///   anotherRole (ChildUnits) : 21, 211, 2111
        /// </remarks>
        [TestInitialize]
        public void TestInitialize()
        {
            _domain = Domain.Build(DomainConfiguration.Load(DomainName));
            _domain.HasRecycleBin = new Random(Environment.TickCount).Next() % 2 == 1;

            _domain.DeleteAll();

            _table = _domain.AddTable(StringProperty.RandomIdentifier());

            //Creating users
            _user01 = _domain.AddUser("user_01", StringProperty.RandomPassword());
            _user11 = _domain.AddUser("user_11", StringProperty.RandomPassword());
            _user111 = _domain.AddUser("user_111", StringProperty.RandomPassword());
            _user112 = _domain.AddUser("user_112", StringProperty.RandomPassword());
            _user1111 = _domain.AddUser("user_1111", StringProperty.RandomPassword());
            _user1121 = _domain.AddUser("user_1112", StringProperty.RandomPassword());
            _user21 = _domain.AddUser("user_21", StringProperty.RandomPassword());
            _user211 = _domain.AddUser("user_211", StringProperty.RandomPassword());
            _user2111 = _domain.AddUser("user_2111", StringProperty.RandomPassword());

            //Creating units
            _unit0 = _domain.AddUnit("unit_0");
            _unit1 = _domain.AddUnit("unit_1");
            _unit11 = _domain.AddUnit("unit_11");
            _unit111 = _domain.AddUnit("unit_111");
            _unit112 = _domain.AddUnit("unit_112");
            _unit2 = _domain.AddUnit("unit_2");
            _unit21 = _domain.AddUnit("unit_21");
            _unit211 = _domain.AddUnit("unit_211");

            _unit0.AddUnit(_unit11);
            _unit1.AddUnit(_unit11);
            _unit11.AddUnit(_unit111);
            _unit11.AddUnit(_unit112);

            _unit2.AddUnit(_unit21);
            _unit21.AddUnit(_unit211);

            //Setting users' units
            _unit0.AddUser(_user01);
            _unit1.AddUser(_user11);
            _unit11.AddUser(_user111);
            _unit11.AddUser(_user112);
            _unit111.AddUser(_user1111);
            _unit112.AddUser(_user1121);
            _unit2.AddUser(_user21);
            _unit21.AddUser(_user211);
            //Adding _unit_11 to another unit
            _unit21.AddUser(_user111);
            _unit211.AddUser(_user2111);

            //Creating roles
            _role = _domain.AddRole("main_role");
            _childRole = _domain.AddRole("child_role");
            _anotherRole = _domain.AddRole("another_role");

            _role.AddRole(_childRole);

            //Granting permissions
            _table.Grant(_role, DataAction.Select, AccessLevel.ChildAndParentUnits);

            _table.Grant(_childRole, DataAction.Select, AccessLevel.ChildUnits);

            _table.Grant(_anotherRole, DataAction.Select, AccessLevel.ChildUnits);

            //Enrolling users in a role
            _childRole.AddUser(_user01);
            _childRole.AddUser(_user11);
            _childRole.AddUser(_user111);
            _childRole.AddUser(_user112);
            _childRole.AddUser(_user1111);
            _childRole.AddUser(_user1121);

            _anotherRole.AddUser(_user21);
            _anotherRole.AddUser(_user211);
            _anotherRole.AddUser(_user2111);
        }

        /// <summary>
        ///   Test cleanup
        /// </summary>
        [TestCleanup]
        public void TestCleanup()
        {
            _domain.DeleteAll();
        }

        /// <summary>
        ///   Deleting a user
        /// </summary>
        [TestMethod]
        public void DeletingUser()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            _user111.Delete();

            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);
        }


        /// <summary>
        ///   Adding user in unit
        /// </summary>
        [TestMethod]
        public void AddingUserInUnit()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            _unit1.AddUser(_user2111);

            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 5);
        }


        /// <summary>
        ///   Deleting user from unit
        /// </summary>
        [TestMethod]
        public void DeletingUserFromUnit()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            _unit11.RemoveUser(_user111);

            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);
        }

        /// <summary>
        ///   Removing a unit child.
        /// </summary>
        [TestMethod]
        public void RemoveUnitChild()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            _unit0.RemoveUnit(_unit11);

            Assert.AreEqual(_unit11.Parents.Count(), 1);

            //Checking that affected users' permissions are refreshed
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 1);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 7);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);
        }

        /// <summary>
        ///   Adding user parent
        /// </summary>
        [TestMethod]
        public void AddingUnitParent()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            _unit21.AddUnit(_unit11);

            Assert.AreEqual(_unit11.Parents.Count(), 3);

            //Checking that affected users' permissions are refreshed
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 7);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 6);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 6);

            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 6);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);
        }


        /// <summary>
        /// Deleting a unit
        /// </summary>
        [TestMethod]
        public void DeletingUnit()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            _unit11.Delete();

            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 1);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 1);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 0);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 1);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 1);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);
        }

        /// <summary>
        /// Adding user to role
        /// </summary>
        [TestMethod]
        public void AddingUserToRole()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            //Creating a role
            var role = _domain.AddRole(StringProperty.RandomIdentifier());

            _table.Grant(role, DataAction.Select, AccessLevel.ParentUnits);

            //Adding a user to the role
            role.AddUser(_user2111);

            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 3);
        }

        /// <summary>
        /// Deleting a user from a role
        /// </summary>
        [TestMethod]
        public void DeletingUserFromRole()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            _childRole.RemoveUser(_user111);

            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 0);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);
        }

        /// <summary>
        /// Deleting a role from a role
        /// </summary>
        [TestMethod]
        public void DeletingRoleFromRole()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            _role.RemoveRole(_childRole);

            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 1);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 1);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);
        }

        /// <summary>
        /// Deleting a role
        /// </summary>
        [TestMethod]
        public void DeletingRole()
        {
            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 8);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);

            _role.Delete();

            Assert.AreEqual(_user01.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user11.TableUnitAccessRights.Count(), 4);
            Assert.AreEqual(_user111.TableUnitAccessRights.Count(), 5);
            Assert.AreEqual(_user112.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user1111.TableUnitAccessRights.Count(), 1);
            Assert.AreEqual(_user1121.TableUnitAccessRights.Count(), 1);
            Assert.AreEqual(_user21.TableUnitAccessRights.Count(), 3);
            Assert.AreEqual(_user211.TableUnitAccessRights.Count(), 2);
            Assert.AreEqual(_user2111.TableUnitAccessRights.Count(), 1);
        }
    }
}